package sisdroid.framework;


import java.lang.reflect.Constructor;
import java.lang.reflect.Type;
import java.util.HashSet;

import android.content.Context;
import android.util.Log;



import sisdroid.framework.rest.RestClient;
import sisdroid.framework.sensors.BluetoothSensor;
import sisdroid.framework.sensors.CellIdSensor;
import sisdroid.framework.sensors.CompositeSensor;
import sisdroid.framework.sensors.EmptySensor;
import sisdroid.framework.sensors.Sensor;
import sisdroid.framework.sensors.GpsSensor;
import sisdroid.framework.sensors.ImeiSensor;
import sisdroid.framework.sensors.WifiSensor;

public class SisClientFactory implements SisFactory
{
	Context owner;
	
	
	public final static int SENSOR_BLUETOOTH	= 1;
	public final static int SENSOR_WIFI			= 2;
	public final static int SENSOR_CELLID		= 4;
	public final static int SENSOR_IMEI			= 8;
	public final static int SENSOR_GPS			= 16;
	
	HashSet< Class<? extends Sensor> > SensorClasses;
	
	// Class to instantiate when one requests a rest client.
	Class<? extends RestClient> restclient;
	
	/**
	 * addCustomSensor.
	 * 
	 * Add a custom sensor to the framework.
	 * 
	 * @param newClass
	 */
	public void addCustomSensor( Class<? extends Sensor> newClass )
	{
		SensorClasses.add( newClass ); 
	}
	
	
	/**
	 * setEnabledStandardSensors.
	 * 
	 * Enables the standard sensors provided by framework.
	 * Use bytewise or to add more. ie for GPS and Bluetooth use
	 * setEnabledStandardSensors( SENSOR_BLUETOOTH | SENSOR_GPS );
	 */
	public void setEnabledStandardSensors( int SensorFlags )
	{
		SensorClasses.clear();
		
		if ( ( SensorFlags & SENSOR_BLUETOOTH ) == SENSOR_BLUETOOTH )
		{
			SensorClasses.add( BluetoothSensor.class );
		}
	
		if ( ( SensorFlags & SENSOR_WIFI ) == SENSOR_WIFI )
		{
			SensorClasses.add( WifiSensor.class );
		}
		
		if ( ( SensorFlags & SENSOR_CELLID ) == SENSOR_CELLID )
		{
			SensorClasses.add( CellIdSensor.class );
		}
		
		if ( ( SensorFlags & SENSOR_IMEI ) == SENSOR_IMEI )
		{
			SensorClasses.add( ImeiSensor.class );
		}
		
		if ( ( SensorFlags & SENSOR_GPS ) == SENSOR_GPS )
		{
			SensorClasses.add( GpsSensor.class );
		}
	
	}
	
	public SisClientFactory( Context owner ) 
	{
		this.owner				= owner;
		this.restclient			= sisdroid.framework.rest.RestClientImpl.class;
		this.SensorClasses		= new HashSet<Class<? extends Sensor>>();
	}

	@Override
	public RestClient createRestClient()
	{
		Object o = null;
		try
		{
			o = restclient.newInstance();
		}
		catch ( Exception e)
		{
			
		}
		// This may look crazy, but what if exception was thrown before?
		if ( RestClient.class.isInstance( o ) )
		{
			return ( RestClient ) o;
		}
		return null;
	}

	@Override
	public Sensor createDiscoverers()
	{
		Sensor r = null;
		
		for ( Class<? extends Sensor> c : this.SensorClasses  )
		{
			// Trick is: if we find constroctor that takes Activity as argument use that
			// else if we find a parameterless ctor, that one is used.
			try
			{
				for ( Constructor<? extends Sensor > ctor : c.getConstructors() )
				{
					Sensor newObject = null;
					Type[] types = ctor.getGenericParameterTypes();
					if ( types.length == 1 )
					{
						if ( types[ 0 ] == Context.class )
						{
							newObject = ctor.newInstance( this.owner );
						}
					} 
					else if (  types.length == 1 )
					{
						newObject = c.newInstance();
					}
					if ( newObject != null )
					{
						if ( r == null )
						{
							r = newObject;
						}
						else
						{
							r = new CompositeSensor( r, newObject );
						}
					}
				}
			}
			catch ( Exception e )
			{
				Log.d( "Factory", e.toString() );
				// Errorhandling is not needed in super code
			}
		}
		if ( r == null )
		{
			r = new EmptySensor();
		}
 		return r;//new CompositeSensor(new CellIdSensor( owner ), new CompositeSensor(new WifiSensor(owner), new CompositeSensor( new GpsSensor( owner ), new ImeiSensor( owner ) ) ) );
	}
}
